package cn.tnar.yunpark.xunlang;

import cn.tnar.yunpark.model.SpaceSensorStatus;
import cn.tnar.yunpark.model.SpaceStatus;
import cn.tnar.yunpark.service.SensorEventDispatcher;
import cn.tnar.yunpark.util.ByteTool;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.DatagramPacket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;


/**
 * author : CaineZhu
 * date   : 2017/12/22
 * desc   : logic handler
 */


public class XunLangMessageHandler extends SimpleChannelInboundHandler<DatagramPacket> {

    Logger logger = LoggerFactory.getLogger(this.getClass().getName());
    private SensorEventDispatcher dispatcher;

    public XunLangMessageHandler(SensorEventDispatcher dispatcher) {
        this.dispatcher = dispatcher;
    }
    private int dataLen = 8;

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {
        ByteBuf buf = packet.copy().content();
        byte[] sourceData = new byte[buf.readableBytes()];
        buf.readBytes(sourceData);
        sourceData = readEscape(sourceData);
        //Arrays.binarySearch()sourceData

        try {

            //数据验证
            int len = sourceData.length;
            //logger.info("bcc:{}", ByteTool.bytes2String(sourceData[len - 2]));
            byte bcc = BCCTool.bccCalc(sourceData, 2, len - 4);
            boolean validate = validation(sourceData) && (bcc == sourceData[len - 2]);
            logger.warn("data validate:{} bcc:{} dataLen:{} receiver data:{}", validate, ByteTool.bytes2String(bcc), len, ByteTool.bytes2String(sourceData));
            if (validate) {
                byte type = sourceData[6];
                byte[] macBytes = new byte[4];
                System.arraycopy(sourceData, 2, macBytes, 0, macBytes.length);
                String mac = ByteTool.bytes2StringWithOutBlank(macBytes);
                switch (type) {

                    case (byte) 0xA8: {//地磁数据上报

                        int year = 2000 + (sourceData[7] & 0xff);
                        int month = sourceData[8] & 0xff;
                        int count = sourceData[9] & 0xff;
                        logger.debug("mac:{},year:{},month:{}", mac, year, month, count);
                        int statusVersion = sourceData[10] & 0xff;
                        int status = (statusVersion >> 7) & 0xff;
                        int version = statusVersion & (byte) 0x0f;
                        logger.debug("status:{} version:{} statusVersion:{}", status > 0 ? 1 : 0, version,statusVersion &0xff);
                        byte[] timeBytes = new byte[4];
                        timeBytes[0] = 0x00;
                        System.arraycopy(sourceData, 11, timeBytes, 1, 3);
                        int fullTime = ByteTool.byte2Int(timeBytes);
                        int day = fullTime >>> 18 & 0x3f;
                        int hour = (fullTime >>> 12 & 0x3f) + 8;//GMT+8
                        int min = fullTime >>> 6 & 0x3f;
                        int sec = fullTime & 0x3f;
                        Calendar calendar = Calendar.getInstance();
                        calendar.set(year, month - 1, day, hour, min, sec);

                        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
                        String dateTime = sdf.format(calendar.getTime());
                        //logger.info("fullTime:{} year:{} month:{} day:{} hour:{} min:{} sec:{}", fullTime, year, month, day, hour, min, sec);
                        byte[] numBytes = new byte[4];
                        System.arraycopy(sourceData, 14, numBytes, 0, 4);
                        String cimi = "46011" + ByteTool.byte2Int(numBytes);
                        short vBatCapacity = ByteTool.byte2Short(sourceData[18], sourceData[19]);
                        //前7位0xFE00 后9位0x1FF
                        double vBattery = (((vBatCapacity >>> 9) & 0x7F) * 4 + 0x6DB) * 0.001664311835d;
                        double vCapacity = ((vBatCapacity & 0x1FF) + 0x6DB) * 0.001664311835d;
                        int csq = sourceData[20] & 0xff;
                        int matchCode = sourceData[21] & 0xff;
                        //logger.info("date:{} cimi:{} csq:{} matchCode:{} vBattery:{} vCapacity:{}", dateTime, cimi, csq, matchCode, vBattery, vCapacity);
                        String statusCode = XunLangUtil.toLbmStatus(status);
                        SpaceStatus event = new SpaceStatus(mac,statusCode , dateTime);
                        logger.info("mac:{} statusCode:{} dateTime:{}",mac,statusCode,dateTime);
                        dispatcher.dispatch(event);//事件分发
                        int power = (int)((vBattery - 2.8d) / 0.009d);
                        SpaceSensorStatus sensorStatus = new SpaceSensorStatus(mac, power, String.valueOf(power),
                                csq, String.valueOf(csq));
                        dispatcher.dispatch(sensorStatus);
                        logger.info("mac:{} power:{} csq:{}",mac,power,csq);
                        reply(macBytes, ctx, packet);
                    }
                    break;

                    case (byte) 0xA9: {//地磁电压电量上报,一天一次
                        int count = sourceData[7] & 0xff;
                        //logger.info("mac:{} commandCount:{}", mac, count);
                        // int command = sourceData[8];
                        // int commandCount = sourceData[9];
                        int statusVersion = sourceData[10] & 0xff;
                        int status = (statusVersion & (byte) 0x80) >> 8 & 0xff;
                        int version = statusVersion & (byte) 0x0f;
                        logger.info("status:{} version:{}", status > 0 ? 1 : 0, version);
                        short vBatCapacity = ByteTool.byte2Short(sourceData[11], sourceData[12]);
                        //前7位0xFE00 后9位0x1FF
                        //前7位0xFE00 后9位0x1FF
                        double vBattery = (((vBatCapacity >>> 9) & 0x7F) * 4 + 0x6DB) * 0.001664311835d;
                        double vCapacity = ((vBatCapacity & 0x1FF) + 0x6DB) * 0.001664311835d;
                        logger.info("vBattery:{} vCapacity:{}", vBattery, vCapacity);
                        reply(macBytes, ctx, packet);
                    }
                    break;
                }

            }

        } catch (Exception e) {
            // e.printStackTrace();
            logger.error("channelRead0 Exception:{}", e.getMessage());
        }
    }

    //数据头尾验证
    public boolean validation(byte[] bs) {
        int len = bs.length;
        if ((bs[0] & bs[1]) == (byte) 0xff && bs[len - 1] == (byte) 0xff && len > dataLen) return true;
        return false;
    }

    //接收转义
    public byte[] readEscape(byte[] source) {
        List<Byte> list = new ArrayList<Byte>();
        List<Byte> target = new ArrayList<Byte>();
        for (int i = 0; i < source.length; i++) {
            list.add(source[i]);
        }

        for (int j = 0; j < list.size(); j++) {
            byte tmp = list.get(j);
            byte tmp1 = (j + 1) == list.size() ? (byte) 0xff : list.get(j + 1);
            if (tmp == (byte) 0xFE && tmp1 == (byte) 0x01) {
                target.add((byte) 0xFF);
                list.remove(j + 1);
            } else if (tmp == (byte) 0xFE && tmp1 == (byte) 0x00) {
                target.add((byte) 0xFE);
                list.remove(j + 1);
            } else {
                target.add(tmp);
            }
        }

        byte[] data = new byte[target.size()];
        for (int k = 0; k < target.size(); k++) {
            data[k] = target.get(k);
        }
        //logger.info("escape:{}",ByteTool.bytes2String(data));
        return data;

    }

    //发送转义
    public byte[] sendEscape(byte[] source) {
        List<Byte> list = new ArrayList<Byte>();
        List<Byte> target = new ArrayList<Byte>();
        for (int i = 0; i < source.length; i++) {
            list.add(source[i]);
        }

        for (int j = 0; j < list.size(); j++) {
            byte tmp = list.get(j);
            if (tmp == (byte) 0x0A) {
                target.add((byte) 0x7D);
                target.add((byte) 0x58);
            } else if (tmp == (byte) 0x7D) {
                target.add((byte) 0x7D);
                target.add((byte) 0x5D);
            } else if (tmp == (byte) 0x00) {
                target.add((byte) 0x7D);
                target.add((byte) 0x57);
            } else {
                target.add(tmp);
            }
        }

        //tail
        target.add((byte) 0x00);//bcc 校验先用0x00代替
//        target.add((byte)0xFF);

        byte[] data = new byte[target.size()];
        for (int k = 0; k < target.size(); k++) {
            data[k] = target.get(k);
        }
        return data;
    }

    //数据响应
    public void reply(byte[] macBytes, ChannelHandlerContext ctx, DatagramPacket packet) {
        byte[] command = {/*(byte)0xFF,(byte)0xFF,*/0x00, 0x00, 0x00, 0x00, 0x01, (byte) 0xA1, 0x01, 0x00};
        System.arraycopy(macBytes, 0, command, 0, macBytes.length);
        byte[] cmd = sendEscape(command);
        int cmdLen = cmd.length;
        cmd[cmdLen - 1] = BCCTool.bccCalc(cmd, 0, cmdLen - 1);
        try {
            ctx.writeAndFlush(new DatagramPacket(
                    Unpooled.copiedBuffer(cmd), packet.sender())).sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
